package com.hh.hot100;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * @author hanghao
 * @date 2023/8/4 16:13
 * 滑动窗口最大值
 * hard
 */
public class No239 {
    //自定义数组 (自定义一个单调数组)
    class MyQueue{
        Deque<Integer> deque = new ArrayDeque<>();
        //弹出元素时，比较当前要弹出的数值是否等于队列出口的数值，如果相等则弹出
        //同时判断队列当前是否为空
        void poll(int val) {
            if(!deque.isEmpty() && val == deque.peek()) {
                deque.poll();
            }
        }
        //添加元素时，如果要添加的元素大于入口处的元素，就将入口元素弹出
        //保证队列元素单调递减
        //比如此时队列元素3,1，2将要入队，比1大，所以1弹出，此时队列：3,2
        void offer(int val) {
            while(!deque.isEmpty() && val > deque.getLast()) {
                deque.removeLast();
            }
            deque.offer(val);
        }
        //队列队顶元素始终为最大值
        int peek(){
            return deque.peek();
        }
    }

    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length == 1) {
            return nums;
        }
        int len =nums.length - k + 1;
        //存放结果元素的数组
        int[] res = new int[len];
        int num = 0;
        //新建一个我们上面定义的单调数组
        MyQueue myQueue = new MyQueue();
        //先将前k的元素放入队列
        for(int i = 0; i < k; i++) {
            myQueue.offer(nums[i]);
        }
        res[num++] = myQueue.peek();
        for (int i = k; i < nums.length; i++) {
            //滑动窗口移除最前面的元素，移除是判断该元素是否放入队列
            myQueue.poll(nums[i - k]);
            //滑动窗口加入最后面的元素
            myQueue.offer(nums[i]);
            //记录对应的最大值
            res[num++] = myQueue.peek();
        }
        return res;
    }
}
